package com.st.service.impl;

import com.api.attractions.IAttractionsClient;
import com.st.entity.Attractions;
import com.st.entity.ESAttractions;
import com.st.entity.SearchPageResult;
import com.st.service.ISearchService;
import com.st.utils.PageResult;
import com.st.utils.Result;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Service
public class SearchServiceImpl implements ISearchService {
    @Autowired
    private ElasticsearchRestTemplate template;

    @Autowired
    private IAttractionsClient iAttractionsClient;


    @Override
    public Result loadData() {
        //删除索引库
        template.deleteIndex(ESAttractions.class);

        //创建索引库
        template.createIndex(ESAttractions.class);
        template.putMapping(ESAttractions.class);
        //1.远程调用st-attractions获取所有的Attractions信息
        List<Attractions> attractions = iAttractionsClient.findAll();
        //2.将spu信息同步到索引库

        attractions.forEach(attraction -> {
            ESAttractions esAttractions = new ESAttractions();
            esAttractions.setAreas(attraction.getAreas());
            esAttractions.setBusinessHours(attraction.getBusinessHours());
            esAttractions.setCity(attraction.getCity());
            esAttractions.setDepartureData(attraction.getDepartureData().toString());
            esAttractions.setFeature(attraction.getFeature());
            esAttractions.setId(attraction.getId());
            esAttractions.setImg(attraction.getImg());
            esAttractions.setIsHot(attraction.getIsHot());
            esAttractions.setName(attraction.getName());
            esAttractions.setPrice(attraction.getPrice());
            esAttractions.setProvince(attraction.getProvince());
            esAttractions.setSite(attraction.getSite());
            esAttractions.setTheme(attraction.getTheme());
            //保存
            template.save(esAttractions);
        });
        return new Result("保存成功",true);
    }

    @Override
    public PageResult<ESAttractions> search(Map searchMap) {
        //1.构建查询条件
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        //match(景点名)
        MatchQueryBuilder nameQueryBuilder = QueryBuilders.
                matchQuery("name",searchMap.get("keyword"));
        //multiMatch(省市区)
        MultiMatchQueryBuilder provinceMatchQueryBuilder = QueryBuilders
                .multiMatchQuery(searchMap.get("keyword"), "province", "city", "areas");
        //match(主题)
        MatchQueryBuilder themeQueryBuilder = QueryBuilders
                .matchQuery("theme", searchMap.get("keyword"));

        boolQueryBuilder.should(nameQueryBuilder);
        boolQueryBuilder.should(provinceMatchQueryBuilder);
        boolQueryBuilder.should(themeQueryBuilder);
        //设置分页
        PageRequest page = null;
        if(!StringUtils.isEmpty(searchMap.get("page"))&&!StringUtils.isEmpty(searchMap.get("size"))){
            Integer pageNow = (Integer) searchMap.get("page");
            Integer size = (Integer) searchMap.get("size");
            page = PageRequest.of(pageNow-1,size);
        }
        //设置高亮
        HighlightBuilder highlightBuilder = getHighlightBuilder("name", "province", "theme","city");


        //聚合
        TermsAggregationBuilder provinceAgg = AggregationBuilders.terms("provinceAgg").field("province");
        TermsAggregationBuilder themeAgg = AggregationBuilders.terms("themeAgg").field("theme");
        TermsAggregationBuilder cityAgg = AggregationBuilders.terms("cityAgg").field("city");

        //5.过滤
        if(!StringUtils.isEmpty(searchMap.get("cityFilter"))){

            TermQueryBuilder cityFilter = QueryBuilders.termQuery("city",searchMap.get("cityFilter"));
            boolQueryBuilder.filter(cityFilter);
        }
        if(!StringUtils.isEmpty(searchMap.get("themeFilter"))){

            TermQueryBuilder themeFilter = QueryBuilders.termQuery("theme",searchMap.get("themeFilter"));
            boolQueryBuilder.filter(themeFilter);
        }





        //
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                .withPageable(page)
                .withHighlightBuilder(highlightBuilder)
                .addAggregation(provinceAgg)
                .addAggregation(themeAgg)
                .addAggregation(cityAgg);
        //排序
        SortBuilder priceSortBuilder = null;
        if(!StringUtils.isEmpty(searchMap.get("priceSort"))){
            if("desc".equals(searchMap.get("priceSort"))){
                priceSortBuilder = SortBuilders.fieldSort("price").order(SortOrder.DESC);
            }else {
                priceSortBuilder = SortBuilders.fieldSort("price").order(SortOrder.ASC);
            }
            builder.withSort(priceSortBuilder);
        }
        NativeSearchQuery build = builder.build();

        SearchHits<ESAttractions> result = template.search(build, ESAttractions.class);
        //总记录数
        long totalHits = result.getTotalHits();
        //取当前页数据
        List<SearchHit<ESAttractions>> searchHits = result.getSearchHits();
        List<ESAttractions> esAttractionsList = new ArrayList();

        //设置高亮
        searchHits.forEach(hit->{
            //取文档信息
            ESAttractions content = hit.getContent();
            //取高亮
            Map<String, List<String>> highlightFields = hit.getHighlightFields();
            Set<String> keySet = highlightFields.keySet();
            keySet.forEach(key->{
                List<String> list = highlightFields.get(key);
                if("name".equals(key)){
                    String highlightValue = list.get(0);
                    content.setName(highlightValue);
                }
                if("province".equals(key)){
                    String highlightValue = list.get(0);
                    content.setProvince(highlightValue);
                }
                if("theme".equals(key)){
                    String highlightValue = list.get(0);
                    content.setTheme(highlightValue);
                }
            });
            esAttractionsList.add(content);
        });
        //获取聚合信息
        Aggregations aggregations = result.getAggregations();
        //获取聚合结果集
        List provinceAggList = new ArrayList();
        Terms provinceAggTerms = aggregations.get("provinceAgg");
        List<? extends Terms.Bucket> provinceBucket = provinceAggTerms.getBuckets();
        provinceBucket.forEach(el->{
            provinceAggList.add(el.getKeyAsString());
        });
        List themeList = new ArrayList();
        Terms themeAggTerms = aggregations.get("themeAgg");
        List<? extends Terms.Bucket> themeAggBucket = themeAggTerms.getBuckets();
        themeAggBucket.forEach(el->{
            themeList.add(el.getKeyAsString());
        });
        List cityList = new ArrayList();
        Terms cityAggTerms = aggregations.get("cityAgg");
        List<? extends Terms.Bucket> cityAggBucket = cityAggTerms.getBuckets();
        cityAggBucket.forEach(el->{
            cityList.add(el.getKeyAsString());
        });
        //pageResult
        SearchPageResult pageResult = new SearchPageResult();
        pageResult.setData(esAttractionsList);
        pageResult.setTotal(totalHits);
        pageResult.setProvinceList(provinceAggList);
        pageResult.setThemeList(themeList);
        pageResult.setCityList(cityList);
        return pageResult;
    }



    // 设置高亮字段
    private HighlightBuilder getHighlightBuilder(String... fields) {
        // 高亮条件
        HighlightBuilder highlightBuilder = new HighlightBuilder(); //生成高亮查询器
        for (String field : fields) {
            highlightBuilder.field(field);//高亮查询字段
        }
        highlightBuilder.requireFieldMatch(false);     //如果要多个字段高亮,这项要为false
        highlightBuilder.preTags("<span style=\"color:red\">");   //高亮设置
        highlightBuilder.postTags("</span>");
        //下面这两项,如果你要高亮如文字内容等有很多字的字段,必须配置,不然会导致高亮不全,文章内容缺失等
        highlightBuilder.fragmentSize(800000); //最大高亮分片数
        highlightBuilder.numOfFragments(0); //从第一个分片获取高亮片段

        return highlightBuilder;
    }
}
